package com.inspinia.base.api.aop;

import com.inspinia.base.api.jwt.JWTConfig;
import com.inspinia.base.api.jwt.JWTGenerator;
import com.inspinia.base.api.service.ExternalInterfaceService;
import com.inspinia.base.common.exception.ApiErrorCode;
import com.inspinia.base.common.model.AjaxResult;
import com.inspinia.base.common.model.BaseConstants;
import com.inspinia.base.util.DateUtil;
import com.inspinia.base.util.JsonUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Date;

/**
 * API拦截器
 *
 * @author fengwx
 */
@Component
public class ApiInterceptor extends HandlerInterceptorAdapter {


    @Resource
    private ExternalInterfaceService externalInterfaceService;

    /**
     * 密钥
     */
    private static final String SECURITY_SIGN = "24878d3edc9214bfe634aad784095c59";

    private String[] apiIgnorePaths = new String[]{"/api/login", "/api/bank/reportResult", "/api/keyGenerator/getKey"};


    @Override
    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) throws Exception {
        boolean needAuth = isAPIAuth(req.getServletPath());
        if (needAuth) {

            //从请求头中获取token
            String token = getSign(req);
            boolean isUrl = externalInterfaceService.addrIsExist(req.getServletPath());
            if (isUrl) {
                //jwt的验证方式
                switch (JWTGenerator.getState(token, JWTConfig.SECRET)) {
                    case VALID:
                        return true;
                    case EXPIRED:
                        writeObj2Res(res, new AjaxResult(false, ApiErrorCode.keyExpired.getCode(), ApiErrorCode.keyExpired.getName()));
                        return false;
                    case INVALID:
                        writeObj2Res(res, new AjaxResult(false, ApiErrorCode.keyAuthenticationFailed.getCode(), ApiErrorCode.keyAuthenticationFailed.getName()));
                        return false;
                    default:
                }
            } else {
                //最简单的校验方式，以当天的日期加上固定字符串md5加密做固定字符串。匹配是否相等。
                //设置时间格式
                String dateNow = DateUtil.formatDate(new Date(),BaseConstants.DATE_PATTERN_D);
                String md5Key = DigestUtils.md5Hex(SECURITY_SIGN + dateNow);
                if (!md5Key.equals(token)) {
                    writeObj2Res(res, new AjaxResult(false, "签名验证失败"));
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 往response中写入对象
     *
     * @param res
     * @param ajaxResult
     * @throws IOException
     */
    private void writeObj2Res(HttpServletResponse res, AjaxResult ajaxResult) throws IOException {
        res.setContentType("application/json");
        res.setCharacterEncoding("UTF-8");
        res.getOutputStream().write(JsonUtils.toJson(ajaxResult).getBytes());
    }


    /**
     * 判断API地址是否需要签名验证
     *
     * @param path 相对路径
     * @return true 表示跳过验证
     */
    private boolean isAPIAuth(String path) {
        return isAPIUrl(path) && ((ArrayUtils.indexOf(apiIgnorePaths, path) == -1));
    }

    /**
     * 是否是api的url
     *
     * @param path
     * @return
     */
    private boolean isAPIUrl(String path) {
        return path.startsWith("/api");
    }

    /**
     * 把http header里的字段转换为对象
     *
     * @param req http request
     * @return
     */
    private String getSign(HttpServletRequest req) {
        return req.getHeader("key");
    }


}
